package com.ebelter.seneo.models.googlefit;


import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.SystemClock;
import android.support.annotation.NonNull;

import com.ebelter.btcomlib.utils.BaseHandle;
import com.ebelter.btcomlib.utils.ThreadManager;
import com.ebelter.btcomlib.utils.ToastUtil;
import com.ebelter.btcomlib.utils.log.LogUtils;
import com.google.android.gms.auth.api.signin.GoogleSignIn;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.android.gms.auth.api.signin.GoogleSignInClient;
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
import com.google.android.gms.auth.api.signin.GoogleSignInResult;
import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.fitness.Fitness;
import com.google.android.gms.fitness.FitnessOptions;
import com.google.android.gms.fitness.data.DataPoint;
import com.google.android.gms.fitness.data.DataSet;
import com.google.android.gms.fitness.data.DataSource;
import com.google.android.gms.fitness.data.DataType;
import com.google.android.gms.fitness.data.Field;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;

import java.util.concurrent.TimeUnit;

import static com.google.android.gms.auth.api.signin.internal.zzh.getSignInResultFromIntent;

public class GoogleFitManager extends BaseHandle {

    private static GoogleFitManager instance;
    private GoogleFitManager(){}

    public static GoogleFitManager getInstance() {

        if (instance==null){
            synchronized (GoogleFitManager.class){
                instance=new GoogleFitManager();
            }
        }
        return instance;
    }

    private static final String TAG = "GoogleFitManager";



    private static final int GOOGLE_SIGN_IN = 120;
    private static final int GOOGLE_FIT_PERMISSIONS_REQUEST_CODE = 121;

    private FitnessOptions fitnessOptions = FitnessOptions.builder()
            //步数
          //  .addDataType(DataType.TYPE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_WRITE)
            //距离
            //.addDataType(DataType.TYPE_DISTANCE_DELTA, FitnessOptions.ACCESS_WRITE)
            //体重
            .addDataType(DataType.TYPE_WEIGHT, FitnessOptions.ACCESS_WRITE)
            //BMR
            .addDataType(DataType.TYPE_BASAL_METABOLIC_RATE, FitnessOptions.ACCESS_WRITE)
            //Fat
            .addDataType(DataType.TYPE_BODY_FAT_PERCENTAGE, FitnessOptions.ACCESS_WRITE)
            .build();






    //获取最后登录的账号 如果为空说明未登录状态
    public GoogleSignInAccount getLastSignedInAccount(Context context){
        GoogleSignInAccount signInAccount=GoogleSignIn.getLastSignedInAccount(context);
        if (signInAccount==null){
            subscribeWeight=false;
            subscribeBMR=false;
            subscribeFat=false;
        }
       return signInAccount;
    }


    //登录
    public void signIn(Activity activity){
        GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN).requestEmail().build();
        GoogleSignInClient mGoogleSignInClient = GoogleSignIn.getClient(activity, gso);
        Intent signInIntent = mGoogleSignInClient.getSignInIntent();
        activity.startActivityForResult(signInIntent, GOOGLE_SIGN_IN);
    }


    private GoogleSignInAccount signInAccount;
    /**
     * 在activity的onActivityResult方法里面调用，回调是否登录账号成功。
     */
    public void handleResult(Activity activity,int requestCode,Intent data,LoginCallback loginCallback) {
        if (requestCode!=GOOGLE_SIGN_IN){
            return;
        }
        try {
            GoogleSignInResult result = getSignInResultFromIntent(data);


            if (result!=null&&result.isSuccess()) {
                LogUtils.i2(TAG,"----谷歌登录成功");
                loginCallback.success();
                signInAccount = GoogleSignIn.getSignedInAccountFromIntent(data).getResult(ApiException.class);
                clearSubscribe();
                sunbscrerib(activity);
            }else {
                loginCallback.failure();
                clearSubscribe();
                LogUtils.i2(TAG,"----谷歌登录失败");
            }
        } catch (ApiException e) {
            LogUtils.i2(TAG,"谷歌登录失败 code=" + e.getStatusCode());
            loginCallback.failure();
            clearSubscribe();
        }
    }

    private void clearSubscribe(){
        subscribeWeight=false;
        subscribeBMR=false;
        subscribeFat=false;
    }

    //订阅
    public void sunbscrerib(Activity activity){
        signInAccount = GoogleSignIn.getLastSignedInAccount(activity.getBaseContext());
        if (signInAccount==null){
            return;
        }
        //判断是否有写入数据的权限，这个会弹出授权写入数据的弹框
        if (!GoogleSignIn.hasPermissions(signInAccount, fitnessOptions)) {
            GoogleSignIn.requestPermissions(
                    activity, // your activity
                    GOOGLE_FIT_PERMISSIONS_REQUEST_CODE,
                    signInAccount,
                    fitnessOptions);
            subscriptionData(activity);
        }else{
            subscriptionData(activity);
        }
    }

    private void subscriptionData(Activity activity) {
        if (!subscribeWeight){
            subscribe(activity,DataType.TYPE_WEIGHT);// 订阅步数
        }

        if (!subscribeFat){
            subscribe(activity,DataType.TYPE_BODY_FAT_PERCENTAGE);// 距离
        }
        if (!subscribeBMR){
            subscribe(activity,DataType.TYPE_BASAL_METABOLIC_RATE);// 距离
        }

    }

    private boolean subscribeSTEP_COUNT_DELTA;//订阅步数成功的标志
    private boolean subscribeDISTANCE_DELTA;//订阅距离成功的标志

    private boolean subscribeWeight;//
    private boolean subscribeBMR;//
    private boolean subscribeFat;//
    // 订阅
    private void subscribe(final Activity activity, final DataType dataType) {
        GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(activity.getBaseContext());
        if (account == null) {
            return;
        }
        Fitness.getRecordingClient(activity, account)
                .subscribe(dataType)
                .addOnSuccessListener(new OnSuccessListener<Void>() {
                    @Override
                    public void onSuccess(Void aVoid) {
                        //每订阅成功一个，会回调这个方法
                        if (DataType.TYPE_WEIGHT==dataType){
                            subscribeWeight=true;
                            LogUtils.i2(TAG,"--------订阅weight成功");
                        }else if (DataType.TYPE_BASAL_METABOLIC_RATE==dataType){
                            subscribeBMR=true;
                            LogUtils.i2(TAG,"--------订阅BMR成功");
                        }else if (DataType.TYPE_BODY_FAT_PERCENTAGE==dataType){
                            subscribeFat=true;
                            LogUtils.i2(TAG,"--------订阅Fat成功");
                        }

                    }
                })
                .addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        if (DataType.TYPE_WEIGHT==dataType){
                            subscribeWeight=false;
                            LogUtils.i2(TAG,"--------订阅weight失败");
                        }else if (DataType.TYPE_BASAL_METABOLIC_RATE==dataType){
                            subscribeBMR=false;
                            LogUtils.i2(TAG,"--------订阅BMR失败");
                        }else if (DataType.TYPE_BODY_FAT_PERCENTAGE==dataType){
                            subscribeFat=false;
                            LogUtils.i2(TAG,"--------订阅Fat失败");
                        }

                        //2秒后再去订阅的意思
                        postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                subscribe(activity,dataType);
                            }
                        },3000);

                    }
                });
    }


    /**
     * //创建要上传的数据对象
     * @param dataType DataType类型
     * @param field Field类型
     * @param values 数据值
     * @param startTime 开始时间戳
     * @param endTime 结束时间戳
     * @return
     * 开始时间戳必须小于结束时间戳，不然就抛异常
     */
    private DataSet createDataForRequest(Context context,DataType dataType, Field field, Object values, long startTime, long endTime) {
        DataSource dataSource = new DataSource.Builder()
                        .setAppPackageName(context)
                        .setDataType(dataType)
                        .setStreamName("streamName")
                        .setType(DataSource.TYPE_RAW)
                        .build();
        DataSet dataSet = DataSet.create(dataSource);

        DataPoint dataPoint = dataSet.createDataPoint().setTimeInterval(startTime, endTime, TimeUnit.MILLISECONDS);

        if (dataType == DataType.TYPE_CALORIES_EXPENDED||dataType==DataType.TYPE_HEART_RATE_BPM) {
            dataPoint.getValue(field).setFloat((Float) values);
        } else {
            //如果是float类型则要调用setFloagValues
            if (values instanceof Integer) {
                dataPoint.setIntValues((Integer) values);
            } else {
                dataPoint = dataPoint.setFloatValues((Float) values);
            }
        }
        dataSet.add(dataPoint);
        return dataSet;
    }


    //插入步数数据
    public void insertStepData(final Activity activity, final int stepAllCount, final long lastUploadTime,
                               final long currentUploadTime, final InsertDataCallback insertDataCallback){
        final Context context=activity.getApplicationContext();
        final GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(context);
        if (account==null){
            insertDataCallback.failure(1,"请先登录Google");
            return;
        }
        ThreadManager.getShortPool().execute(new Runnable() {
            @Override
            public void run() {
                DataSet stepDataSet = createDataForRequest(context,DataType.TYPE_STEP_COUNT_DELTA,Field.FIELD_STEPS,stepAllCount,lastUploadTime,currentUploadTime);
                Task<Void> responseStep = Fitness.getHistoryClient(activity, account).insertData(stepDataSet);
                //等待任务完成
                while(!responseStep.isComplete()) {
                    SystemClock.sleep(300);
                }
                insertDataCallback.success();
            }
        });

    }


    //插入步数数据
    public void insertWeight(final Context context, final float value, final long lastUploadTime,
                               final long currentUploadTime, final InsertDataCallback insertDataCallback){
        final Context context2=context.getApplicationContext();
        final GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(context2);
        if (account==null){
            insertDataCallback.failure(1,"请先登录Google");
            return;
        }
        ThreadManager.getShortPool().execute(new Runnable() {
            @Override
            public void run() {
                DataSet stepDataSet = createDataForRequest(context,DataType.TYPE_WEIGHT,Field.FIELD_WEIGHT,value,lastUploadTime,currentUploadTime);
                Task<Void> responseStep = Fitness.getHistoryClient(context2, account).insertData(stepDataSet);
                //等待任务完成
                long startTime=System.currentTimeMillis();
                while(!responseStep.isComplete()&&System.currentTimeMillis()-startTime<10000) {
                    SystemClock.sleep(300);
                }
                if (responseStep.isComplete()){
                    insertDataCallback.success();
                }else {
                    insertDataCallback.failure(2,"insertWeight插入时间超时");
                }

            }
        });


    }




    //插入步数数据
    public void insertFat(final Context context, final float value, final long lastUploadTime,
                             final long currentUploadTime, final InsertDataCallback insertDataCallback){
        final Context context2=context.getApplicationContext();
        final GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(context2);
        if (account==null){
            insertDataCallback.failure(1,"请先登录Google");
            return;
        }
        ThreadManager.getShortPool().execute(new Runnable() {
            @Override
            public void run() {
                DataSet stepDataSet = createDataForRequest(context,DataType.TYPE_BODY_FAT_PERCENTAGE,Field.FIELD_PERCENTAGE,value,lastUploadTime,currentUploadTime);
                Task<Void> responseStep = Fitness.getHistoryClient(context2, account).insertData(stepDataSet);
                //等待任务完成
                long startTime=System.currentTimeMillis();
                while(!responseStep.isComplete()&&System.currentTimeMillis()-startTime<10000) {
                    SystemClock.sleep(300);
                }
                if (responseStep.isComplete()){
                    insertDataCallback.success();
                }else {
                    insertDataCallback.failure(2,"insertFat插入时间超时");
                }

            }
        });


    }


    //插入步数数据
    public void insertBmr(final Context context, final float value, final long lastUploadTime,
                          final long currentUploadTime, final InsertDataCallback insertDataCallback){
        final Context context2=context.getApplicationContext();
        final GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(context2);
        if (account==null){
            insertDataCallback.failure(1,"请先登录Google");
            return;
        }
        ThreadManager.getShortPool().execute(new Runnable() {
            @Override
            public void run() {
                DataSet stepDataSet = createDataForRequest(context,DataType.TYPE_BASAL_METABOLIC_RATE,Field.FIELD_BPM,value,lastUploadTime,currentUploadTime);
                Task<Void> responseStep = Fitness.getHistoryClient(context2, account).insertData(stepDataSet);
                //等待任务完成
                long startTime=System.currentTimeMillis();
                while(!responseStep.isComplete()&&System.currentTimeMillis()-startTime<10000) {
                    SystemClock.sleep(300);
                }
                if (responseStep.isComplete()){
                    insertDataCallback.success();
                }else {
                    insertDataCallback.failure(2,"insertBmr插入时间超时");
                }

            }
        });


    }







    public interface InsertDataCallback{
        void success();
        void failure(int error, String desc);
    }

    public interface LoginCallback{
        void success();
        void failure();
    }



}
